/*
 * IoBuffer.cpp
 *
 *  Created on: 2013. 7. 23.
 *      Author: ncanis
 */
#include "stdafx.h"
#include "IoBuffer.h"

namespace TED {

IoBuffer::IoBuffer(INT32 capacity) {
	this->position = 0;
	this->limit = 0;
	this->capacity = 0;

	SetAutoExpand(capacity);
	this->limit = capacity;
}

IoBuffer::~IoBuffer() {
	delete buf;
}

BYTE* IoBuffer::toBuf() {
	return this->buf;
}

INT32 IoBuffer::Position() {
	return this->position;
}

INT32 IoBuffer::Limit() {
	return this->limit;
}

IoBuffer& IoBuffer::Flip() {
	this->limit = position;
	this->position = 0;
	return *this;
}
IoBuffer& IoBuffer::Rewind() {
	this->position = 0;
	return *this;
}
IoBuffer& IoBuffer::Mark() {
	this->mark = position;
	return *this;
}
IoBuffer& IoBuffer::Reset() {
	this->position = mark;
	return *this;
}

void IoBuffer::SetAutoExpand(UINT32 length) {
	INT newCapacity = position + length;
	if (newCapacity > capacity) {
		BYTE* newBuf = new BYTE[newCapacity];
		INT oldSize = 0;
		if (!buf) {
			oldSize = capacity * sizeof(BYTE);
			// CopyMemory faster than MoveMemory
			CopyMemory(newBuf, buf, oldSize);
		}

		ZeroMemory(newBuf+oldSize, newCapacity*sizeof(BYTE)); //나머지 영역 0으로 초기화
		this->capacity = newCapacity;
		if (!buf) {
			delete buf;
		}
		this->buf = newBuf;
	}
}

IoBuffer& IoBuffer::Slice(BYTE* const data, INT32 length) {
	GetData(data,length);
	return *this;
}

/////////////////////////////////////////////////////////////////////////////////////

IoBuffer& IoBuffer::AddTChars(TCHAR* const t, INT length) {
	if (length < 0) {
		length = _tcslen(t); // 
	}
	int mSize = length*sizeof(TCHAR);
	AddInt32(mSize); // add TCHAR* 길이 등록
	SetAutoExpand(mSize);
	AddData(t, mSize);
	return *this;
}

IoBuffer& IoBuffer::AddBytes(BYTE* const t, INT size) {
	if (size < 0) {
		size =sizeof(t);
	}
	SetAutoExpand(size);
	AddData(t, size);
	return *this;
}

IoBuffer& IoBuffer::AddByte(const BYTE data) {
	AddData(&data, sizeof(BYTE));
	return *this;
}
IoBuffer& IoBuffer::AddInt16(const INT16 data) {
	AddData(&data, sizeof(INT16));
	return *this;
}
IoBuffer& IoBuffer::AddInt32(const INT32 data) {
	AddData(&data, sizeof(INT32));
	return *this;
}
IoBuffer& IoBuffer::AddInt64(const INT64 data) {
	AddData(&data, sizeof(INT64));
	return *this;
}
IoBuffer& IoBuffer::AddFloat(const FLOAT data) {
	AddData(&data, sizeof(FLOAT));
	return *this;
}

/////////////////////////////////////////////////////////////////////////////////////

IoBuffer& IoBuffer::GetTChars(TCHAR* const t) {
	INT32 mSize = GetInt32(); // get TCHAR* 길이
	GetData(t, mSize);
	return *this;
}

IoBuffer& IoBuffer::GetBytes(BYTE* const t, INT length) {
	GetData(t, length);
	return *this;
}

BYTE IoBuffer::GetByte() {
	BYTE value = 0;
	GetData(&value, sizeof(BYTE));
	return value;
}

INT32 IoBuffer::GetInt32() {
	INT32 value = 0;
	GetData(&value, sizeof(INT32));
	return value;
}
INT16 IoBuffer::GetInt16() {
	INT16 value = 0;
	GetData(&value, sizeof(INT16));
	return value;
}
FLOAT IoBuffer::GetFloat() {
	FLOAT value = 0;
	GetData(&value, sizeof(FLOAT));
	return value;
}

INT64 IoBuffer::GetInt64() {
	INT64 value = 0;
	GetData(&value, sizeof(INT64));
	return value;
}

void IoBuffer::ToHexDump() {
	INT32 length = limit*4;
	TCHAR* hexstr = new TCHAR[length];
	GetHexDump(hexstr, length*sizeof(TCHAR));
	Logger::Get().Debug(_T("IoBuffer(pos=%d,limit=%d,capacity=%d)=%s"),position, limit, capacity, hexstr);	

	// 주의: 할당된 데이터보다 더 많은 크기를 초기화하는경우 delete할때 corruption error이 발생하게 된다.
	delete []hexstr;
}

void IoBuffer::GetHexDump(TCHAR* const hexstr, int mSize) {
	ZeroMemory(hexstr,mSize);

	INT32 i=0;
	INT32 pos =0;
	INT32 h_len = 3; //헥사 표시 공간(3자리)
	for (i=0; i<limit; i++) {		
		if(pos>mSize/sizeof(TCHAR)) break;

		// 주어진 크기만큼 복사한다.
		_stprintf_s(hexstr+pos, h_len*sizeof(TCHAR), _T("%02x "), buf[i]);
		pos+=h_len;		
	}	
}

// IoBuffer object toString overload.
std::ostream& operator<<(std::ostream &os, IoBuffer* buf) {
	INT32 length = buf->limit*4;
	TCHAR* hexstr = new TCHAR[length];
	buf->GetHexDump(hexstr, length*sizeof(TCHAR));
	os<<hexstr;
	delete[] hexstr;
	return os;
}

} /* namespace ted */
